#include <QSettings>
#include "httprequest.h"
#include "log.h"
#include "httpconnector.h"
#include "cookiestorage.h"

namespace Wishmaster {

	static const char* PostDelimiter = "----AaB03x";

	HttpRequest::HttpRequest(HttpConnector* parent, const QUrl& url, const QString& type) :
			m_parent(parent),
			m_url(url),
			m_requestType(type),
			m_data(),
			m_redirect(false),
			m_progressCounter(0),
			m_reply(NULL)
	{
		log(llDebug, "Http host: %s", qPrintable(url.host()));

		m_triesCount = 0;

		QSettings settings;
		m_userAgent = settings.value("connection/useragent", "Wishmaster").toString();
	}

	QString HttpRequest::host() const
	{
		return m_url.host();
	}

	QString HttpRequest::path() const
	{
		return m_url.path();
	}

	void HttpRequest::slot_result()
	{
		if(m_parent->cookieStorage())
		{
			QString cookie = QString::fromAscii(m_reply->rawHeader("Set-Cookie"));
			m_parent->cookieStorage()->setCookieString(m_url.host(), cookie);
		}
		if(m_reply->error() != QNetworkReply::NoError)
		{
			log(llDebug, "Error: %s", qPrintable(m_reply->errorString()));
			m_parent->requestFinished(id(), true);
			return;
		}
		log(llDebug, "Request done: %d(%s:%s)", getStatusCode(),
				qPrintable(m_url.host()),
				qPrintable(m_url.path()));

		killTimer(m_timerID);
		RequestPtr ptr = m_parent->request(id());

		m_redirect = false;
		QUrl redirection = m_reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
		if(!redirection.isEmpty() && (m_requestType == "GET"))
		{
			m_referer = m_url.toString();
			if(redirection.path().startsWith('/'))
				m_url = redirection;
			else
				m_url.setPath(m_url.path() + '/' + redirection.path());

			m_reply->deleteLater();
			m_reply = NULL;

			perform();
			m_redirect = true;
			return;
		}
		if(m_reply->hasRawHeader("Content-type"))
			m_contentType = m_reply->rawHeader("Content-type");
		else
			log(llWarning, "Unknown content-type");

		if(!ptr)
			log(llWarning, "HttpRequest::slot_result: Null ptr");
		emit result(ptr, m_reply->readAll());
		m_reply->deleteLater();
		m_reply = NULL;
		m_parent->requestFinished(id(), false);
	}

	QString HttpRequest::contentType() const
	{
		return m_contentType;
	}

	bool HttpRequest::error()
	{
		return m_error;
	}

	int HttpRequest::getStatusCode()
	{
		if(!m_reply)
			return 0;
		return m_reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toUInt();
	}

	void HttpRequest::timerEvent(QTimerEvent* event)
	{
		log(llDebug, "Timeout: %s", m_url.path().toAscii().data());
		if(!m_reply)
			return;
		m_reply->abort();
		killTimer(m_timerID);
		if(++m_triesCount > Retries)
		{
			log(llDebug, "XYNTA: %s", m_url.path().toAscii().data());
			m_error = true;
			//emit progress(100, 100);
			emit result(m_parent->request(id()), QByteArray());
			return;
		}
		perform();
	}

	void HttpRequest::perform()
	{
		QNetworkRequest request;
		request.setUrl(m_url);
		request.setRawHeader("User-Agent", m_userAgent.toAscii());
		request.setRawHeader("Accept", "text/html, application/xml;q=0.9, application/xhtml+xml, image/png, image/jpeg, image/gif, image/x-xbitmap, */*;q=0.1");
		request.setRawHeader("Accept-Charset", "iso-8859-1, utf-8, utf-16, *;q=0.1");
		request.setRawHeader("Accept-Encoding", "deflate");

		if(!m_referer.isEmpty())
			request.setRawHeader("Referer", m_referer.toAscii());

		if(m_parent->cookieStorage())
		{
			log(llDebug, "urlhost: %s", qPrintable(m_url.host()));
			QString cookies = m_parent->cookieStorage()->cookieString(m_url.host());
			if(!cookies.isEmpty())
			{
				request.setRawHeader("Cookie", cookies.toAscii());
				request.setRawHeader("Cookie2", "$Version=1");
			}
		}

		request.setRawHeader("Connection", "Keep-Alive, TE");
		request.setRawHeader("TE", "deflate, chunked, identity, trailers");

		if(m_requestType == "POST")
		{
			request.setRawHeader("Content-Type", QString("multipart/form-data; boundary=%1").arg(PostDelimiter).toAscii());
			m_data.append("--").append(PostDelimiter).append("--").append("\r\n");
			request.setHeader(QNetworkRequest::ContentLengthHeader, m_data.length());
			m_reply = m_parent->manager()->post(request, m_data);
		}
		else
		{
			m_reply = m_parent->manager()->get(request);
		}
		connect(m_reply, SIGNAL(finished()), this, SLOT(slot_result()));
		connect(m_reply, SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(slot_progress(qint64,qint64)));
		m_timerID = startTimer(RecvTimeout);
		log(llDebug, "[%d]Request::perform(): %s", id(), qPrintable(m_url.host() + m_url.path()));
	}

	void HttpRequest::slot_progress(qint64 done, qint64 total)
	{
		if(++m_progressCounter >= 10 || done == total)
		{
			m_progressCounter = 0;
			emit progress(done, total);
			killTimer(m_timerID);
			m_timerID = startTimer(RecvTimeout);
		}
	}

	void HttpRequest::clearPostData()
	{
		m_data.clear();
	}

	void HttpRequest::addPostField(const QString& fieldname, const QString& fielddata)
	{
		m_data.append("--").append(PostDelimiter).append("\r\n");
		m_data.append(QString("Content-Disposition: form-data; name=\"%1\"\r\n\r\n%2\r\n").arg(fieldname).arg(fielddata).toUtf8());
	}

	void HttpRequest::addPostFile(const QString& fieldname, const QString& filename, const QByteArray& filedata)
	{
		m_data.append("--").append(PostDelimiter).append("\r\n");
		if(filedata.isEmpty())
		{
			m_data.append(QString("Content-Disposition: form-data; name=\"%1\"; filename=\"\"\r\n\r\n\r\n").arg(fieldname));
		}
		else
		{
			m_data.append(QString("Content-Disposition: form-data; name=\"%1\"; filename=\"%2\"\r\n").arg(fieldname).arg(filename));
			m_data.append("Content-Transfer-Encoding: binary\r\n\r\n");
			m_data.append(filedata);
			m_data.append("\r\n");
		}
	}

	void HttpRequest::setReferer(const QString& referer)
	{
		m_referer = referer;
	}

	void HttpRequest::parseSetCookie(const QString& cookie)
	{
		QStringList list = cookie.split(";");
		foreach(QString entry, list)
		{
			int eqpos = entry.indexOf("=");
			if(eqpos < 0)
				continue;
			QString key = entry.left(eqpos).trimmed();
			QString value = entry.mid(eqpos + 1).trimmed();
			m_cookieMap[key] = value;
		}
	}

	QString HttpRequest::cookie(const QString& key)
	{
		return m_cookieMap[key];
	}

	void HttpRequest::cancel()
	{
		if(!m_reply)
			return;
		m_reply->abort();
		m_parent->dequeue(id());
	}

} // namespace Wishmaster
